package org.club.Controller;

import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.club.Service.PublicService;
import org.club.Service.FileOssService;
import org.club.common.model.dto.UsersDto;
import org.club.common.model.entity.BusinessException;
import org.club.common.model.vo.UserVo;
import org.club.common.util.ApiResponseMe;
import org.club.common.util.JwtUtil;
import org.club.common.util.KaptchaUtils;
import org.club.common.util.RedisCacheHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import java.awt.image.BufferedImage;
import java.io.IOException;


//该类用于不需要验证码身份的接口（登录、注册、重置密码、验证码）
@Tag(name = "不需要验证码身份的接口", description = "登录、注册、重置密码、验证码")
@RestController
@RequestMapping("/club")
@Slf4j
public class PublicController {
    @Autowired
    private RedisCacheHelper redisCacheHelper;//Redis
    @Autowired
    private FileOssService fileOssService;//文件上传
    @Autowired
    private PublicService publicService;
    @Autowired
    private JwtUtil jwtUtil;

    /**
     * 生成并返回验证码图片和验证码的key
     * 该方法使用KaptchaUtils工具类生成验证码图片和文本，然后将文本存储在Redis中，并返回验证码的key和图片数据
     *
     * @return ApiResponseMe对象，包含验证码的key和图片数据如果生成失败，返回错误信息
     */
    @GetMapping("/kaptcha")
    public ApiResponseMe kaptcha() {
        try {
            KaptchaUtils kaptcha = new KaptchaUtils();
            BufferedImage image = kaptcha.getImage();
            String codeText = kaptcha.getText();
            System.out.println("验证码" + codeText);
            // 将验证码文本存储在Redis中，并获取存储的key
            String key = redisCacheHelper.setVerifyCode(codeText, 3);
            System.out.println("验证码key:" + key);
            // 将图片转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "JPEG", baos);
            byte[] imageBytes = baos.toByteArray();
            Map<String, Object> data = new HashMap<>();
            data.put("verifyCode", key);
            data.put("image", imageBytes);
            return ApiResponseMe.success(data);
        } catch (Exception e) {
            e.printStackTrace();
            return ApiResponseMe.error(500, "获取验证码失败");
        }
    }


    /**
     * 处理用户注册请求
     *
     * @param file    用户头像文件，通过multipart/form-data格式传输
     * @param userDto 用户注册信息，包括用户名、密码等，通过multipart/form-data格式传输
     * @return 返回注册结果的ApiResponseMe对象
     */
    @PostMapping("/register")
    public ApiResponseMe register(@RequestPart("file") MultipartFile file, @RequestPart("users") UsersDto userDto) {

        // 调用服务层方法进行用户注册，并传入用户信息和头像文件
        Integer i = publicService.registerWithAvatar(userDto, file);
        if (i == 1) {
            // 注册成功，返回成功信息
            return ApiResponseMe.shape(true, "注册成功");
        }
        // 注册失败，返回失败信息
        return ApiResponseMe.error(400, "注册失败");

    }


    /**
     * 处理用户登录请求
     *
     * @param userDto  用户登录信息，包含用户名和密码
     * @param response 用于向客户端返回数据的响应对象
     * @return 返回一个包含用户信息的ApiResponseMe对象
     */
    @PostMapping("/login")
    public ApiResponseMe login(@RequestBody UsersDto userDto, HttpServletResponse response) {
        UserVo userVo = publicService.login(userDto);
        Cookie cookie = new Cookie("token", userVo.getToken());
        cookie.setHttpOnly(true);
        cookie.setSecure(true);
        cookie.setPath("/");
        cookie.setMaxAge(86400);
        response.addCookie(cookie);
        userVo.setToken(null);
        return ApiResponseMe.success(userVo);
    }


    /**
     * 验证用户token的有效性
     * 此方法通过读取请求中的cookie来获取token信息，并验证其有效性
     * 如果token有效，返回成功响应；如果token无效或已过期，返回相应的错误响应
     *
     * @param token 从cookie中获取的用户token
     * @return ApiResponseMe对象，包含验证结果和相关状态信息
     */
    @GetMapping("/verify-token")
    public ApiResponseMe verifyToken(@CookieValue(name = "token", required = false) String token) {
        if (token == null || token.isEmpty()) {
            return ApiResponseMe.error(401, "未登录");
        }
        log.info("处理前的token" + token);
        String substring = token.substring(5);
        log.info("处理后的token" + substring);

        //验证token的有效性
        if (jwtUtil.validateToken(substring)) {
            return ApiResponseMe.success(true);
        }
        return ApiResponseMe.error(401, "token已过期");

    }

    /**
     * 处理用户登出请求的控制器方法
     * 该方法通过POST请求接收用户的登出请求，并通过清除认证令牌（token）来实现用户登出
     *
     * @param response 用于添加响应中的Cookie
     * @return 返回一个HTTP 200响应，表示用户已成功登出
     */
    @PostMapping("/logout")
    public ResponseEntity<?> logout(HttpServletResponse response) {
        Cookie cookie = new Cookie("token", null);
        cookie.setHttpOnly(true);
        cookie.setSecure(true);
        // 设置Cookie的作用路径，这里设置为根路径，确保覆盖所有路径的token
        cookie.setPath("/");
        // 设置Cookie的过期时间为0，使其立即过期
        cookie.setMaxAge(0);
        // 将创建的Cookie添加到HTTP响应中
        response.addCookie(cookie);
        // 返回一个HTTP200响应，表示用户已成功登出
        return ResponseEntity.ok().build();
    }


    /**
     * 处理重置密码请求的控制器方法
     * <p>
     * 该方法用于接收POST请求，并根据用户提供的信息进行密码重置操作
     * 它接受一个UsersDto对象作为请求体，其中包含了重置密码所需的信息
     *
     * @param userDto 包含用户信息的DTO对象，用于密码重置
     * @return 返回一个ApiResponseMe对象，包含操作结果的信息
     */
    @PostMapping("/resetPassword")
    public ApiResponseMe resetPassword(@RequestBody UsersDto userDto) {
        // 调用服务层方法进行密码重置，并传入用户信息
        Integer i = publicService.resetPassword(userDto);
        if (i > 0) {
            return ApiResponseMe.shape(true, "重置密码成功");
        }
        // 重置密码成功，返回成功信息
        return ApiResponseMe.error(400, "重置密码失败");
    }



    /**
     * 处理文件上传请求
     * 该方法使用@PostMapping注解，表示它仅响应POST方法的请求
     * 请求的路径为"/upload"，且期望接收一个名为"file"的文件作为请求的一部分
     *
     * @param file 一个MultipartFile对象，代表上传的文件
     * @return 返回一个字符串，通常是一个URL或状态消息，表示文件上传的结果
     */
    @PostMapping("/upload")
    public String upload(@RequestPart("file") MultipartFile file) {
        // 调用fileOssService的uploadToOss方法来处理文件上传到OSS（对象存储服务）
        // 这里不直接处理上传逻辑，而是委托给专门的服务去做，以保持控制器的简洁和职责清晰
        return fileOssService.uploadToOss(file);
    }

}
